﻿//处理DOM或模板（Templates）的实用类。能以JavaScript较清晰地编写HTML片段（HTML fragments）或DOM。
Ext.DomHelper = {
    emptyTags: /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
    confRe: /tag|children|cn|html$/i,
    endRe: /end/i,

    //返回元素的装饰（markup） ，是一段html片段
    //o : Object  DOM对象（包含子孙）
    //o中的 “属性：值” 将被以 “属性=值” 的方式加入到html标签中（除tag、children、cn、cls、html属性外，因为他们另有用途）
    /*
    tag : 元素的html标记名
    children : 也可以是cn，一个数组，装了与o参数同性质的元素，用来递归地把子标签、内容等放入父标签中
    cls : 将解析成“class=值”放在html标记中
    html : 元素的innerHTML内容
    */
    markup: function (o) {
        var b = '',
            attr,
            val,
            key,
            keyVal,
            cn;

        if (typeof o == "string") {//如果o是字符串，则返回值直接是该字符串
            b = o;
        }
        else if (Ext.isArray(o)) {//如果o是数组，则返回值是各字符串的连接，各字符串是装饰后的字符串
            for (var i = 0; i < o.length; i++) {
                if (o[i]) {
                    b += this.markup(o[i]);
                }
            };
        }
        else {//如果o是对象
            b += '<' + (o.tag = o.tag || 'div');//解析html标签，默认为div
            for (attr in o) {
                if (!o.hasOwnProperty(attr)) {
                    continue;
                }
                val = o[attr];
                if (!this.confRe.test(attr)) {//如果属性不是tag|children|cn|html（这四个属性另有用途）
                    if (typeof val == "object") {//如果属性是对象，以“attr = { key: value }”的形式，在b后面加字符串
                        b += ' ' + attr + '="';
                        for (key in val) {
                            if (!val.hasOwnProperty(key)) {
                                continue;
                            }
                            b += key + ':' + val[key] + ';';
                        };
                        b += '"';
                    }
                    else {//否则以“attr = value”的形式在b后面加字符串
                        b += ' ' + ({ cls: 'class', htmlFor: 'for'}[attr] || attr) + '="' + val + '"';
                    }
                }
            };

            //如果参数的tag属性是br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col
            if (this.emptyTags.test(o.tag)) {//直接加闭合反尖括号
                b += '/>';
            }
            else {//否则，加了反尖括号后还要加内容，然后再加闭合尖括号
                b += '>';
                if ((cn = o.children || o.cn)) {//如果参数有children属性或cn属性
                    b += this.markup(cn);//通过递归调用本方法，在b后面加装饰后的字符串
                }
                else if (o.html) {//如果参数有html属性，在b后面直接加html属性值
                    b += o.html;
                }
                b += '</' + o.tag + '>';//加对应的反尖括号
            }
        }
        return b;
    },

    //把指定的样式应用到元素 
    //el : String/HTMLElement  样式所应用的元素 
    //styles : String/Object/Function  表示样式的特定格式字符串，如“width:100px”，或是对象的形式如{width:"100px"}，
    //或是能返回这些格式的函数 
    applyStyles: function (el, styles) {
        if (styles) {
            var i = 0,
                len,
                style;

            el = Ext.fly(el);//获取el对应的轻量级Element元素
            if (typeof styles == 'function') {
                styles = styles.call();
            }
            if (typeof styles == 'string') {//处理字符串形式的styles
                styles = Ext.util.Format.trim(styles).split(/\s*(?::|;)\s*/);
                for (len = styles.length; i < len; ) {
                    el.setStyle(styles[i++], styles[i++]);
                }
            } else if (Ext.isObject(styles)) {//处理对象形式的styles
                el.setStyle(styles);
            }
        }
    },

    //插入HTML片断到Dom 
    //where : String  插入的html要放在元素的哪里 - beforeBegin, afterBegin, beforeEnd, afterEnd. 
    //el : HTMLElement  元素内容 
    //html : String  HTML片断 
    //返回值： HTMLElement  新节点 
    insertHtml: function (where, el, html) {
        var hash = {},
            hashVal,
            setStart,
            range,
            frag,
            rangeEl,
            rs;

        where = where.toLowerCase();


        hash['beforebegin'] = ['BeforeBegin', 'previousSibling'];
        hash['afterend'] = ['AfterEnd', 'nextSibling'];

        range = el.ownerDocument.createRange();
        setStart = 'setStart' + (this.endRe.test(where) ? 'After' : 'Before');
        if (hash[where]) {
            range[setStart](el);
            frag = range.createContextualFragment(html);
            el.parentNode.insertBefore(frag, where == 'beforebegin' ? el : el.nextSibling);
            return el[(where == 'beforebegin' ? 'previous' : 'next') + 'Sibling'];
        }
        else {
            rangeEl = (where == 'afterbegin' ? 'first' : 'last') + 'Child';
            if (el.firstChild) {
                range[setStart](el[rangeEl]);
                frag = range.createContextualFragment(html);
                if (where == 'afterbegin') {
                    el.insertBefore(frag, el.firstChild);
                }
                else {
                    el.appendChild(frag);
                }
            }
            else {
                el.innerHTML = html;
            }
            return el[rangeEl];
        }

        throw 'Illegal insertion point -> "' + where + '"';
    },

    //创建新的Dom元素并插入到el之前  
    //el : String/HTMLElement/Element  元素内容 
    //o : Object/String  指定的Dom对象（和子孙）或是原始的HTML部分 
    //returnElement : Boolean  （可选的）true表示返回一个Ext.Element 
    //返回值：HTMLElement/Ext.Element  新节点 
    insertBefore: function (el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'beforebegin');
    },

    //创建新的Dom元素并插入到el之后   
    //el : String/HTMLElement/Element  元素内容 
    //o : Object/String  指定的Dom对象（和子孙）或是原始的HTML部分 
    //returnElement : Boolean  （可选的）true表示返回一个Ext.Element 
    //返回值：HTMLElement/Ext.Element  新节点 
    insertAfter: function (el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'afterend', 'nextSibling');
    },

    //创建新的Dom元素并插入到el中，元素是第一个孩子。  
    //el : String/HTMLElement/Element  元素内容 
    //o : Object/String  指定的Dom对象（和子孙）或是原始的HTML部分 
    //returnElement : Boolean  （可选的）true表示返回一个Ext.Element 
    //返回值：HTMLElement/Ext.Element  新节点 
    insertFirst: function (el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'afterbegin', 'firstChild');
    },

    //创建新的Dom元素并加入到el中 
    //el : String/HTMLElement/Element  元素内容 
    //o : Object/String  指定的Dom对象（和子孙）或是原始的HTML部分 
    //returnElement : Boolean  (可选的) true表示返回一个Ext.Element 
    append: function (el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'beforeend', '', true);
    },

    //创建新的Dom元素并覆盖el的内容 
    //el : String/HTMLElement/Element  元素内容 
    //o : Object/String  指定的Dom对象（和子孙）或是原始的HTML部分 
    //returnElement : Boolean  (可选的) true表示返回一个Ext.Element 
    //返回值：HTMLElement/Ext.Element  新节点 
    overwrite: function (el, o, returnElement) {
        el = Ext.getDom(el);
        el.innerHTML = this.markup(o);
        return returnElement ? Ext.get(el.firstChild) : el.firstChild;
    },

    doInsert: function (el, o, returnElement, pos, sibling, append) {
        var newNode = this.insertHtml(pos, Ext.getDom(el), this.markup(o));
        return returnElement ? Ext.get(newNode, true) : newNode;
    }
};